---
title: CompletableFuture
description: Future 不推荐使用，CompletableFuture 允许将多种操作连接在一起
---


```java title='将任务传递给 CompletableFuture::runAsync,这样就会执行 QuittableTask.run(),并返回 CompletableFuture<Void>。由于 run() 不回返回，所以在最后调用了 CompletableFuture 来调用 join() ,以等待任务完成。'
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.IntStream;
/**
 * @author 王开琦
 */
public class QuttingCompletable {
    public static void main(String[] args) {
        List<QuittableTask> tasks = IntStream.range(1, QuittableTasks.COUNT).mapToObj(QuittableTask::new).toList();
        List<CompletableFuture<Void>> completableFutures = tasks.stream().map(CompletableFuture::runAsync).toList();
        new Nap(1);
        tasks.forEach(QuittableTask::quit);
        completableFutures.forEach(CompletableFuture::join);
    }
}
```

在上例中，任务是由 CompletableFuture 来管理的 (虽然可以选择实现自定义的 ExecutorService)。无需调用 shutdown() ,除非显式的调用 join() ，否则程序会在第一时间退出，而不会等待任务的完成。
## 基本用法
```java title='随便写的一个有限状态机，，work() 方法使状态机从一个状态移动到下一个状态，并请求了 100 毫秒来执行该 work.'
package pub.wkq.thread;

/**
 * @author 王开琦
 */
public class Machina {
    public Machina(int id) {
        this.id = id;
    }

    public enum State {
        STATE, ONE, TWO, THREE, END;

        State step() {
            if (equals(END)) {
                return END;
            }
            return values()[ordinal() + 1];
        }
    }

    private State state = State.STATE;
    private final int id;

    public static Machina work(Machina m) {
        if (!m.state.equals(State.END)) {
            new Nap(0.1);
            m.state = m.state.step();
        }
        System.out.println(m);
        return m;
    }

    @Override
    public String toString() {
        return "Machina  " +
                "id: " + id +
                (state.equals(State.END) ? "completable":this.state);
    }
}
```
```java title='利用CompletableFuture，通过 completedFuture() 方法来包装一个对象'
package pub.wkq.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 王开琦
 */
public class CompletableMachina {
    public static void main(String[] args) {
        CompletableFuture<Machina> completableFuture = CompletableFuture.completedFuture(new Machina(0));
        try {
            Machina machina = completableFuture.get(); //不会阻塞
            System.out.println("machina = " + machina);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}
```
completedFuture() 创建了一个”已完成“的 CompletableFuture。这种 Future 唯一能做的事情就是 get() 内部对象。

一般来说，get() 会阻塞正在等待结果的被调用线程。该阻塞可以通过 InterruptedException 或 ExecutionException 来退出。在上例中，由于 CompletableFuture 已经完成，因此永远不回发生阻塞，当时就能的得到结果。

一旦将 Machina 用 CompletableFuture 包装起来，就可以通过在 CompletableFuture 上增加操作来控制其包含的对象：

```java title='将Machina对象用 CompletableFuture 包装起来。就可以通过在 CompletableFuture 上增加操作来控制其包含的对象。'
package pub.wkq.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author 王开琦
 */
public class CompletableApply {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Machina> cf = CompletableFuture.completedFuture(new Machina(0));
        CompletableFuture<Machina> cf2 = cf.thenApply(Machina::work);
        CompletableFuture<Machina> cf3 = cf2.thenApply(Machina::work);
        CompletableFuture<Machina> cf4 = cf3.thenApply(Machina::work);
        CompletableFuture<Machina> cf5 = cf4.thenApply(Machina::work);
        Machina machina = cf5.get();
        System.out.println("machina = " + machina);

    }
}
```
thenApply() 用到了一个接收输入并生成输出的 Function。work 方法返回和输入相同的类型，由此每个 CompletableFuture 都仍旧是 Machina 类型。但是，类似于 Stream 中的 map ，Function 也可以返回不同的类型。

CompletableFuture ： 当执行某个操作时，它们会自动对其所携带的对象拆开包装，再重新包装。

```java title='可以消除中间变量，将多个操作串联起来，就像我们使用 Stream 时那样'
package pub.wkq.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author 王开琦
 */
public class CompletableApplyChained {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Machina> completableFuture = CompletableFuture.completedFuture(new Machina(0))
                .thenApply(Machina::work)
                .thenApply(Machina::work)
                .thenApply(Machina::work)
                .thenApply(Machina::work)
                ;
    }
}
```
使用 CompletableFuture 有个重要的好处。默认情况下，通过 thenApply() 来应用函数并不会产生任何通信。这是函数式编程的基础之一，也是它如此适合并发的原因之一。并行流和 CompletableFuture 便是基于这些原则而设计的。只要你决定怎么样都不共享数据，就可以写出相当安全的并发程序。

操作是通过调用 thenApply() 开始的，CompletableFuture 的创建过程会等到所有任务都完成后才会完成。但更多的价值还是在于可以开启所有的任务，然后你就可以在任务运行时继续做其它的事情。通过在最后增加 Async 来实现该效果。

```java
package pub.wkq.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author 王开琦
 */
public class CompletableFutureAsync {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Machina> cf = CompletableFuture.completedFuture(new Machina(0))
                .thenApplyAsync(Machina::work)
                .thenApplyAsync(Machina::work)
                .thenApplyAsync(Machina::work)
                .thenApplyAsync(Machina::work)
                ;


        System.out.println("222" );
        Machina machina = cf.get();
        System.out.println("machina： "+machina);
        System.out.println("hahsh" );
    }
}
```
同步调用，意味着”完成工作后返回“，而异步调用则意味着”立即返回同时在后台继续工作”。 在没有执行 cf.join() 的时候，程序在任务完成前就退出了。对 join() 的调用会一直阻塞 main() 线程的执行。直到 cf 操作完成。

通过 Async 调用，CompletableFuture 会为你管理所有的回调。。
## 其它操作
```java title='创建两个工具类'
package pub.wkq.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author 王开琦
 */
public class CompletableUtilities {
    //获取并展示 CF 中存储的值
    public static void showr(CompletableFuture<?> completableFuture) {
        try {
            System.out.println(completableFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    //针对无值的 CF 操作
    public static void voidr(CompletableFuture<Void> completableFuture) {
        try {
            completableFuture.get();//返回void
        } catch (InterruptedException|ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}

```
